#include <math.h>

#include <util/msg.h>
#include <util/mem.h>
#include <util/common_macros.h>

#include "segment.h"

static boolean __segment_destroy(ImpObject * object) {
	//ImpSegment * s;
	//s = IMP_SEGMENT(object);
	return TRUE;
}

static void __segment_class_init(ImpObjectClass * klass) {
	klass->object_clone = NULL;
	klass->object_destroy = __segment_destroy;
	klass->object_attributes = NULL;
}

static void __segment_init(ImpObject * object) {
	ImpSegment * s;
	s = IMP_SEGMENT(object);

	s->v[0] = NULL;
	s->v[1] = NULL;
}

ImpSegmentClass * imp_segment_get_class(void) {
	static ImpSegmentClass * klass = NULL;

	if (klass == NULL) {
		ImpObjectClassInfo segment_info = {
			"ImpSegment",
			sizeof (ImpSegment),
			sizeof (ImpSegmentClass),
			(ImpObjectClassInitFunc) __segment_class_init,
			(ImpObjectInitFunc) __segment_init,
			(ImpArgSetFunc) NULL,
			(ImpArgGetFunc) NULL
		};

		ImpObjectClass * parent_class = imp_object_get_class();
		ImpObjectClass * segment_class = imp_object_class_new(parent_class, &segment_info);
		klass = IMP_SEGMENT_CLASS(segment_class);
	}
	return klass;
}

ImpSegment * imp_segment_new(ImpVertex * v1, ImpVertex * v2) {
	ImpSegment * s;

	_return_val_if_fail(v1 && v2, NULL);
	_return_val_if_fail(v1 != v2, NULL);

	s = IMP_SEGMENT(imp_object_new(IMP_OBJECT_CLASS(imp_segment_get_class())));

	imp_segment_set(s, v1, v2);

	return s;
}

void imp_segment_set(ImpSegment * s, ImpVertex * v1, ImpVertex * v2) {
	s->v[0] = v1;
	s->v[1] = v2;
	imp_vertex_add_segment(v1, s);
	imp_vertex_add_segment(v2, s);
}

real imp_segment_length2(ImpSegment * s) {

	ImpPoint * p1, * p2;
	real x, y;

	p1 = IMP_POINT(s->v[0]);
	p2 = IMP_POINT(s->v[1]);

	x = p1->x - p2->x;
	y = p1->y - p2->y;

	return (x * x + y * y);
}

real imp_segment_length(ImpSegment * s) {
	return sqrt(imp_segment_length2(s));
}

ImpVertex * imp_segment_get_common_vertex(ImpSegment * s1, ImpSegment * s2) {

	if (s1->v[0] == s2->v[0]) return s1->v[0];
	
	if (s1->v[0] == s2->v[1]) return s1->v[0];

	if (s1->v[1] == s2->v[0]) return s1->v[1];

	if (s1->v[1] == s2->v[1]) return s1->v[1];

	return NULL;
}


real imp_segment_compare_min_y(ImpSegment * s1, ImpSegment * s2) {
	real y1, y2;
	y1 = MIN(IMP_POINT(s1->v[0])->y, IMP_POINT(s1->v[1])->y);
	y2 = MIN(IMP_POINT(s2->v[0])->y, IMP_POINT(s2->v[1])->y);
	return y1 - y2;
}